package visitor;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
import syntaxtree.*;

public class BDDMapGenerator extends GJDepthFirst<String, String> {
	public Vector<String> vMap;
	public Vector<String> hMap;
	public Vector<String> tMap;
 	public Vector<String> mMap;
 	public Vector<String> nMap;
 	public Vector<String> iMap;

	public BDDMapGenerator() {
		vMap = new Vector<String>();
		hMap = new Vector<String>();
		tMap = new Vector<String>();
		nMap = new Vector<String>();
		iMap = new Vector<String>();
		mMap = new Vector<String>();
//		tMap.add("int[]");
//		tMap.add("boolean");
//		tMap.add("int");
	}
	
	public String visit(Goal g, String scope) {
		g.mainClass.accept(this, scope);
		for (Enumeration<Node> nodes = g.nodeListOptional.elements(); nodes
				.hasMoreElements();) {
			Node node = nodes.nextElement();
			node.accept(this, scope);
		}
		tMap.add("int[]");
		tMap.add("boolean");
		tMap.add("int");
		
		try {
			FileWriter variable = new FileWriter("variable.map");
			BufferedWriter out = new BufferedWriter(variable);
			for (int i = 0; i < vMap.size(); i++) 
				out.write(vMap.get(i) + "\n");
			out.close();
			
			FileWriter heap = new FileWriter("heap.map");
			out = new BufferedWriter(heap);
			for (int i = 0; i < hMap.size(); i++) 
				out.write(hMap.get(i) + "\n");
			out.close();
			
			FileWriter heapinvoke = new FileWriter("heapinvoke.tuples");
			out = new BufferedWriter(heapinvoke);
			out.write("# H0:32 I0:32\n");
			for (int i = 0; i < hMap.size(); i++) 
				out.write(hMap.get(i) + " " + hMap.get(i) + "\n");
			out.close();
			
			FileWriter type = new FileWriter("type.map");
			out = new BufferedWriter(type);
			for (int i = 0; i < tMap.size(); i++) 
				out.write(tMap.get(i) + "\n");
			out.close();
			
			FileWriter name = new FileWriter("name.map");
			out = new BufferedWriter(name);
			for (int i = 0; i < nMap.size(); i++) 
				out.write(nMap.get(i) + "\n");
			out.close();
			
			FileWriter invoke = new FileWriter("invoke.map");
			out = new BufferedWriter(invoke);
			for (int i = 0; i < iMap.size(); i++) 
				out.write(iMap.get(i) + "\n");
			out.close();
			
			FileWriter method = new FileWriter("method.map");
			out = new BufferedWriter(method);
			for (int i = 0; i < mMap.size(); i++) 
				out.write(mMap.get(i) + "\n");
			out.close();
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("vMap: " + " " + vMap.size() + vMap);
		System.out.println("hMap: " + " " + hMap.size() + hMap);
		System.out.println("tMap: " + " " + tMap.size() + tMap);
		System.out.println("nMap: " + " " + nMap.size() + nMap);
		System.out.println("iMap: " + " " + iMap.size() + iMap);
		System.out.println("mMap: " + " " + mMap.size() + mMap);
		return null;
	}

	public String visit(VarDeclaration vd, String scope) {
		String var = vd.identifier.accept(this, scope);
		this.vMap.add(scope + "." + var);
		return var;
	}
	
	public String visit(Identifier id, String scope) {
		return id.nodeToken.tokenImage;
	}
	
	public String visit(FormalParameter fp, String scope) {
		String var = fp.identifier.accept(this, scope);
		this.vMap.add(scope + "." + var);
		return var;
	}
	
	public String visit(ArrayAllocationExpression aae, String scope) {
		String alloc = aae.hashCode() + ".new_" + aae.nodeToken1.tokenImage + aae.nodeToken2.tokenImage + aae.nodeToken3.tokenImage;
		aae.expression.accept(this, scope);
		this.vMap.add(scope + "." + aae.hashCode());
		this.hMap.add(alloc);
		this.iMap.add(alloc);
		return alloc;
	}
	
	public String visit(AllocationExpression ae, String scope) {
		String alloc = ae.hashCode() + ".new_" + ae.identifier.accept(this, scope);
		this.vMap.add(scope + "." + ae.hashCode());
		this.hMap.add(alloc);
		this.iMap.add(alloc);
		return alloc;
	}
	
	public String visit(MainClass mc, String scope) {
		
		String type = mc.identifier.accept(this, scope);
		scope = type + "." + mc.nodeToken5.tokenImage;
		
		this.mMap.add(scope);
		mc.identifier1.accept(this, scope);
		mc.printStatement.accept(this, scope);
		this.tMap.add(type);
		
		
		return type;
	}

	public String visit(ClassDeclaration cd, String scope) {
		String type = cd.identifier.accept(this, scope);
		scope = type;
		
		//this.mMap.add(type + ".new_" + type);
		cd.nodeListOptional.accept(this, scope);
		cd.nodeListOptional1.accept(this, scope);
		this.tMap.add(type);
		
		return type;
	}
	
	public String visit(ClassExtendsDeclaration ced, String scope) {
		String type = ced.identifier.accept(this, scope);
		scope = type;
		
		ced.identifier1.accept(this, scope);
		//this.mMap.add(type + ".new_" + type);
		ced.nodeListOptional.accept(this, scope);
		ced.nodeListOptional1.accept(this, scope);
		this.tMap.add(type);
		
		return type;
	}
	
	public String visit(MethodDeclaration md, String scope) {
		
		String nname = md.identifier.accept(this, scope);
		scope += "." + nname;
		
		md.type.accept(this, scope);
		md.nodeOptional.accept(this, scope);
		md.nodeListOptional.accept(this, scope);
		md.nodeListOptional1.accept(this, scope);
		md.expression.accept(this, scope);
		
		this.mMap.add(scope);
		
		return null;
	}
	
	public String visit(MessageSend ms, String scope) {
		String invoke = null;
		ms.nodeOptional.accept(this, scope);
		invoke = ms.identifier.accept(this, scope);
		if (nMap.indexOf(invoke) == -1) {
			nMap.add(invoke);
		}
		invoke = ms.primaryExpression.accept(this, scope) + "." + ms.identifier.accept(this, scope) + "@" + ms.hashCode();
		this.iMap.add(invoke);
		return invoke;
	}
	
	public String visit(Expression expr, String scope) {
		return expr.nodeChoice.accept(this, scope);
	}

	public String visit(PrimaryExpression pe, String scope) {
		return pe.nodeChoice.accept(this, scope);
	}
	
	public String visit(BracketExpression be, String scope) {
		return be.expression.accept(this, scope); 
	}
}
